bitkeeper revision 1.764.1.1 (4048c0e77koAHUIwNvQFG76iV0Alrg)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Fri, 5 Mar 2004 18:03:19 +0000 (18:03 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Fri, 5 Mar 2004 18:03:19 +0000 (18:03 +0000)
evtchn.h, control_if.h:
  new file
Many files:
  Bidirectional consoles for domains >0. Run 'tools/xend/xend' and telnet to the port printed by xc_dom_create.py. (eg. 'telnet localhost 9600').
.del-xen_read_console.c~2a30ac556d6835c7:
  Delete: tools/misc/xen_read_console.c

24 files changed:
.rootkeys
tools/examples/xc_dom_create.py
tools/misc/Makefile
tools/misc/xen_read_console.c [deleted file]
tools/xc/lib/xc_linux_build.c
tools/xend/Makefile
tools/xend/xend.c
xen/arch/i386/mm.c
xen/arch/i386/setup.c
xen/arch/i386/smpboot.c
xen/arch/i386/traps.c
xen/common/event_channel.c
xen/common/kernel.c
xen/common/page_alloc.c
xen/common/schedule.c
xen/include/xeno/config.h
xen/include/xeno/mm.h
xenolinux-2.4.25-sparse/arch/xeno/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c
xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
xenolinux-2.4.25-sparse/arch/xeno/kernel/time.c
xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h [new file with mode: 0644]
xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h [new file with mode: 0644]
xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h

index 05626ddd48aa986585df473ae221c9f042af31ec..c7c8cc401065d56998f30ecf83ebe9019043081d 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
@@ -64,7 +64,6 @@
 3f8bcf29ulZIC9rC4wM70H_q4s6VPg tools/misc/xen_log.c
 3f13d81eQ9Vz-h-6RDGFkNR9CRP95g tools/misc/xen_nat_enable
 3f13d81e6Z6806ihYYUw8GVKNkYnuw tools/misc/xen_nat_enable.README
-3f1668d4F29Jsw0aC0bJEIkOBiagiQ tools/misc/xen_read_console.c
 4022a73cEKvrYe_DVZW2JlAxobg9wg tools/nsplitd/Makefile
 4022a73cKms4Oq030x2JBzUB426lAQ tools/nsplitd/nsplitd.c
 3fbca441SjQr8vJwTQIgH1laysaWog tools/xc/Makefile
 3e5a4e66rw65CxyolW9PKz4GG42RcA xenolinux-2.4.25-sparse/drivers/char/tty_io.c
 3e5a4e669uzIE54VwucPYtGwXLAbzA xenolinux-2.4.25-sparse/fs/exec.c
 3e5a4e66wbeCpsJgVf_U8Jde-CNcsA xenolinux-2.4.25-sparse/include/asm-xeno/bugs.h
+4048c0ddxnIa2GpBAVR-mY6mNSdeJg xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h
 3e5a4e66HdSkvIV6SJ1evG_xmTmXHA xenolinux-2.4.25-sparse/include/asm-xeno/desc.h
+4048c0e0_P2wUTiT6UqgPhn0s7yFcA xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h
 3e5a4e66SYp_UpAVcF8Lc1wa3Qtgzw xenolinux-2.4.25-sparse/include/asm-xeno/fixmap.h
 3e5a4e67w_DWgjIJ17Tlossu1LGujQ xenolinux-2.4.25-sparse/include/asm-xeno/highmem.h
 3e5a4e67YtcyDLQsShhCfQwPSELfvA xenolinux-2.4.25-sparse/include/asm-xeno/hw_irq.h
index 43d9e7ec0f112557f57c0a791530232c1a2a3dbd..b0fa8ad16ae4e1c117a3336cc64ce365413a9dc2 100755 (executable)
@@ -236,6 +236,12 @@ def make_domain():
             xc.domain_destroy ( dom=id )
             sys.exit()
 
+    ports = xc.evtchn_open( dom2=id )
+    if not ports:
+        print "Error creating initial event channel"
+        xc.domain_destroy ( dom=id )
+        sys.exit()
+
     # setup the virtual block devices
 
     # set the expertise level appropriately
@@ -277,7 +283,7 @@ def make_domain():
         xc.domain_destroy ( dom=id )
         sys.exit()
 
-    return id
+    return (id, 9600+ports['port1'])
 # end of make_domain()
 
 def mkpidfile():
@@ -305,8 +311,8 @@ def death_handler(dummy1,dummy2):
 # The starting / monitoring of the domain actually happens here...
 
 # start the domain and record its ID number
-current_id = make_domain()
-output("VM started in domain %d" % current_id)
+(current_id, current_port) = make_domain()
+output("VM started in domain %d. Console I/O available on TCP port %d." % (current_id,current_port))
 
 # if the auto_restart flag is set then keep polling to see if the domain is
 # alive - restart if it is not by calling make_domain() again (it's necessary
@@ -337,6 +343,6 @@ if auto_restart:
            output("Auto-restart daemon: Domain %d has terminated, restarting VM in new domain"
                                      % current_id)
             rmpidfile()
-           current_id = make_domain()
+           (current_id, current_port) = make_domain()
             mkpidfile()
-           output("Auto-restart daemon: VM restarted in domain %d" % current_id)
+           output("Auto-restart daemon: VM restarted in domain %d. Console on port %d." % (current_id,current_port))
index 38edf8e3aa21ddce3e8f326b55e5a476f4849c1b..6e394d804330c539c98d55d8b2ba6b2fc02353a0 100644 (file)
@@ -7,7 +7,7 @@ HDRS     = $(wildcard *.h)
 SRCS     = $(wildcard *.c)
 OBJS     = $(patsubst %.c,%.o,$(SRCS))
 
-TARGETS  = xen_read_console xen_cpuperf
+TARGETS  = xen_cpuperf
 
 INSTALL  = $(TARGETS) xen-mkdevnodes xen_nat_enable xen-clone 
 
diff --git a/tools/misc/xen_read_console.c b/tools/misc/xen_read_console.c
deleted file mode 100644 (file)
index 1352de8..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/******************************************************************************
- * Test program for reading console lines from DOM0 port 666.
- */
-
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int main(void)
-{
-    unsigned char buf[208], filtered[208];
-    struct sockaddr_in addr, from;
-    int fromlen = sizeof(from), i, j;
-    int len, fd = socket(PF_INET, SOCK_DGRAM, 0);
-    
-    if ( fd < 0 )
-    {
-        fprintf(stderr, "could not open datagram socket\n");
-        return -1;
-    }
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_addr.s_addr = htonl(0xa9fe0100); /* 169.254.1.0 */
-    addr.sin_port = htons(666);
-    addr.sin_family = AF_INET;
-    if ( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 )
-    {
-        fprintf(stderr, "could not bind to local address and port\n");
-        return -1;
-    }
-
-    while ( (len = recvfrom(fd, buf, sizeof(buf), 0, 
-                            (struct sockaddr *)&from, &fromlen)) 
-            >= 0 )
-    {
-#if 0
-        unsigned char abuf[32];
-        printf("%d-byte message from %s:%d --\n", len,
-               inet_ntop(AF_INET, &from.sin_addr, abuf, sizeof(abuf)),
-               ntohs(from.sin_port));
-#endif
-        /* For sanity, clean up the string's tail. */
-        if ( buf[len-1] != '\n' ) { buf[len] = '\n'; len++; }
-        buf[len] = '\0';
-
-        for ( i = 0, j = 0; i < len; i++ )
-            if ( (buf[i] == '\n') || (buf[i] == '\0') ||
-                 ((buf[i] >= 32) && (buf[i] <= 126)) )
-                filtered[j++] = buf[i];
-
-        printf("[%d] %s", ntohs(from.sin_port), filtered);
-
-        fromlen = sizeof(from);
-    }
-
-    return 0;
-}
index 32b1515557d2cc2e7c2717cc24d9c934c55b5d41..786d372c3970fe6abb1eea4dabb995f4da6527b2 100644 (file)
@@ -322,7 +322,7 @@ int xc_linux_build(int xc_handle,
         goto error_out;
     }
 
-    if ( ramdisk_name != NULL )
+    if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
     {
         initrd_fd = open(ramdisk_name, O_RDONLY);
         if ( initrd_fd < 0 )
index d07088151982b618df9a56429761d8f7f56fde4d..619f98097528cb2afcbfec14b2bd12efe0660d26 100644 (file)
@@ -1,7 +1,7 @@
 
 CC       = gcc
 CFLAGS   = -Wall -O3 
-CFLAGS  += -I../xc/lib
+CFLAGS  += -I../xc/lib -I../../xenolinux-sparse/include
 
 HDRS     = $(wildcard *.h)
 OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
index 208db8da0d1ca096f83482d3cfd4f5f53f319ad3..ef6e903ddd532933895703d99762ccebc3f29000 100644 (file)
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/mman.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
+#include <signal.h>
 #include <xc.h>
+#include <asm-xeno/control_if.h>
 
 /* NB. The following should be kept in sync with the kernel's evtchn driver. */
 #define EVTCHN_DEV_NAME  "/dev/xen/evtchn"
 #define DOM0_HINT() HINT("You must execute this daemon " \
                          "on a privileged Xenolinux instance (e.g., DOM0).")
 
-/* The following is to be shared with guest kernels. */
-typedef struct {
-    u8 cmd_type;     /* echoed in response */
-    u8 cmd_subtype;  /* echoed in response */
-    u8 id;           /* echoed in response */
-    u8 length;       /* number of bytes in 'msg' */
-    unsigned char msg[60]; /* command-specific message data */
-} control_msg_t;
-#define CONTROL_RING_SIZE 8
-typedef unsigned int CONTROL_RING_IDX;
-#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
-typedef struct {
-    control_msg_t tx_ring[CONTROL_RING_SIZE]; /* guest -> DOM0 */
-    control_msg_t rx_ring[CONTROL_RING_SIZE]; /* DOM0 -> guest */
-    CONTROL_RING_IDX tx_req_prod, tx_resp_prod;
-    CONTROL_RING_IDX rx_req_prod, rx_resp_prod;
-} control_comms_t;
-#define CMD_CONSOLE      0
-#define CMD_CONSOLE_DATA 0
-
-#define PAGE_SHIFT 12
-#define PAGE_SIZE  (1<<PAGE_SHIFT)
-
-typedef struct {
+#if 0
+#define DPRINTF(_f, _a...)  \
+    fprintf ( stdout, _f "\n" , ## _a );
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+/* Per-port Tx/Rx buffering. */
+#define CONBUFSZ 65536
+#define MASK_CONBUF_IDX(_i) ((_i)&(CONBUFSZ-1))
+
+struct portinfo;
+typedef struct portinfo {
     u64              dom;
-    control_comms_t *comms;
+    control_if_t    *interface;
     CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
-    CONTROL_RING_IDX rx_req_cons, rx_resp_prod;
+    CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
+    char            *tx_buf, *rx_buf;
+    unsigned int     txp, txc, rxp, rxc;
+#define CONSTAT_CLOSED    0
+#define CONSTAT_LISTENING 1
+#define CONSTAT_CONNECTED 2
+    int              con_fd, con_status;
+    struct portinfo **pprev, *next; /* links to other active ports */
 } portinfo_t;
 
-static portinfo_t portinfo[1024];    
+#define PORT(_pinfo) ((_pinfo)-portinfo)
+#define TX_EMPTY(_pinfo) ((_pinfo)->txp == (_pinfo)->txc)
+#define TX_FULL(_pinfo)  (((_pinfo)->txp - (_pinfo)->txc) == CONBUFSZ)
+#define RX_EMPTY(_pinfo) ((_pinfo)->rxp == (_pinfo)->rxc)
+#define RX_FULL(_pinfo)  (((_pinfo)->rxp - (_pinfo)->rxc) == CONBUFSZ)
+
+static portinfo_t *active_head;   /* linked list of active ports */
+static portinfo_t portinfo[1024]; /* array of all ports */    
+static int xc_fd, evt_fd, mem_fd;
+
+#define PAGE_SIZE           4096 /* size of a machine page frame            */
+#define BATCH_SIZE           512 /* maximum notifications to read at a time */
+
+static int make_consock_listener(portinfo_t *pinfo);
+static int make_consock_connected(portinfo_t *pinfo);
+static void make_consock_closed(portinfo_t *pinfo);
+static void do_consock_read(portinfo_t *pinfo);
+static void do_consock_write(portinfo_t *pinfo);
+static int process_evtchn_reads(portinfo_t *pinfo);
+static int process_evtchn_writes(portinfo_t *pinfo);
 
-static control_comms_t *map_comms(int fd, unsigned long pfn)
+static control_if_t *map_control_interface(int fd, unsigned long pfn)
 {
     char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
-                       MAP_SHARED, fd, pfn << PAGE_SHIFT);
+                       MAP_SHARED, fd, pfn * PAGE_SIZE);
     if ( vaddr == MAP_FAILED )
         return NULL;
-    return (control_comms_t *)(vaddr + 2048);
+    return (control_if_t *)(vaddr + 2048);
 }
 
-static void unmap_comms(int fd, control_comms_t *c)
+static void unmap_control_interface(int fd, control_if_t *c)
 {
     char *vaddr = (char *)c - 2048;
     (void)munmap(vaddr, PAGE_SIZE);
 }
 
-#define PORT_CHUNK 4
+/* Returns TRUE if the channel is open on exit. */
+static int handle_channel_exception(unsigned int port)
+{
+    xc_dominfo_t info;
+    unsigned int remote_port, status;
+    u64          remote_dom;
+    u16          wbuf;
+    portinfo_t  *pinfo = &portinfo[port];
+
+    if ( xc_evtchn_status(xc_fd, DOMID_SELF, port, 
+                          &remote_dom, &remote_port, &status) != 0 )
+    {
+        SYS_ERROR("Unexpected failure when obtaining port-%d status.", port);
+        exit(1);
+    }
+    
+    if ( status != EVTCHNSTAT_connected )
+    {
+        DPRINTF("Port %d not connected: cleaning up.", port);
+        if ( pinfo->interface != NULL )
+        {
+            unmap_control_interface(mem_fd, pinfo->interface);
+            pinfo->interface = NULL;
+            *(pinfo->pprev) = pinfo->next;
+            if ( pinfo->next != NULL )
+                pinfo->next->pprev = pinfo->pprev;
+            make_consock_closed(pinfo);
+            free(pinfo->tx_buf);
+            free(pinfo->rx_buf);
+            memset(pinfo, 0, sizeof(*pinfo));
+        }
+        /* Cleanup sanity: we'll be the grim reaper. */
+        wbuf = port | PORT_NORMAL;
+        (void)write(evt_fd, &wbuf, sizeof(wbuf));
+        wbuf = port | PORT_DISCONNECT;
+        (void)write(evt_fd, &wbuf, sizeof(wbuf));
+        if ( status == EVTCHNSTAT_disconnected )
+            (void)xc_evtchn_close(xc_fd, DOMID_SELF, port);
+        return 0;
+    }
+
+    /* We only deal with initial ports (id == 0). */
+    if ( remote_port != 0 )
+        return 0;
+
+    if ( pinfo->interface == NULL )
+    {
+        DPRINTF("New control interface for DOM%llu on port %d.", 
+                remote_dom, port);
+        if ( xc_domain_getinfo(xc_fd, remote_dom, 1, &info) != 1 )
+        {
+            SYS_ERROR("Failed to obtain DOM%llu status.", remote_dom);
+            exit(1);
+        }
+        memset(pinfo, 0, sizeof(*pinfo));
+        pinfo->interface = 
+            map_control_interface(mem_fd, info.shared_info_frame);
+        pinfo->tx_buf = malloc(CONBUFSZ);
+        pinfo->rx_buf = malloc(CONBUFSZ);
+        pinfo->dom = remote_dom;
+        pinfo->con_status = CONSTAT_CLOSED;
+        if ( !make_consock_listener(pinfo) )
+        {
+            ERROR("Could not start console %d in listener status.",
+                  PORT(pinfo));
+            exit(1);
+        }
+        pinfo->pprev = &active_head;
+        if ( (pinfo->next = active_head) != NULL )
+            pinfo->next->pprev = &pinfo->next;
+        active_head = pinfo;
+    }
+
+    return 1;
+}
+
+static void process_channel(unsigned int port)
+{
+    portinfo_t      *pinfo = &portinfo[port];
+    u16              wbuf = port;
+
+    /* Acknowledge the notification. */
+    (void)write(evt_fd, &wbuf, sizeof(wbuf));
+
+    /* Process requests; send notification if we updated either ring. */
+    if ( process_evtchn_reads(pinfo) || process_evtchn_writes(pinfo) )
+        (void)xc_evtchn_send(xc_fd, port);
+}
+
 int main(int argc, char **argv)
 {
-    int fd, memfd, xch, chunk;
-    unsigned int bytes, i, port, portid, status;
-    u64 domid;
-    u16 buf[PORT_CHUNK];
+    struct pollfd polls[1025]; /* one per port, plus /dev/xeno/evtchn */
+    portinfo_t *pinfo;
+    unsigned int batch, bytes, i, port, fd_idx;
+    u16 buf[BATCH_SIZE];
 
-    if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
+    /* Ignore writes to disconnected sockets. We clear up later. */
+    (void)signal(SIGPIPE, SIG_IGN);
+    
+    if ( (evt_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR)) == -1 )
     {
         SYS_ERROR("Could not open '%s'", EVTCHN_DEV_NAME);
         ROOT_HINT();
@@ -104,14 +214,14 @@ int main(int argc, char **argv)
         exit(1);
     }
 
-    if ( (memfd = open("/dev/mem", O_RDWR)) == -1 )
+    if ( (mem_fd = open("/dev/mem", O_RDWR)) == -1 )
     {
         SYS_ERROR("Could not open '/dev/mem'");
         ROOT_HINT();
         exit(1);
     }
 
-    if ( (xch = xc_interface_open()) == -1 )
+    if ( (xc_fd = xc_interface_open()) == -1 )
     {
         SYS_ERROR("Could not open Xen control interface");
         ROOT_HINT();
@@ -119,76 +229,388 @@ int main(int argc, char **argv)
         exit(1);
     }
 
-    while ( (bytes = read(fd, buf, sizeof(buf))) == -1 )
+    for ( ; ; )
     {
-        if ( errno == EINTR )
+        polls[0].fd     = evt_fd;
+        polls[0].events = POLLIN;
+
+        fd_idx = 1;
+        for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next )
+        {
+            switch ( pinfo->con_status )
+            {
+            case CONSTAT_LISTENING:
+                polls[fd_idx].fd     = pinfo->con_fd;
+                polls[fd_idx].events = POLLIN;
+                fd_idx++;
+                break;
+            case CONSTAT_CONNECTED:
+                polls[fd_idx].fd     = pinfo->con_fd;
+                polls[fd_idx].events = POLLIN | (RX_EMPTY(pinfo)?0:POLLOUT);
+                fd_idx++;
+                break;
+            }
+        }
+
+        while ( poll(polls, fd_idx, -1) == -1 )
+        {
+            if ( errno == EINTR )
+                continue;
+            SYS_ERROR("Unexpected error from poll().");
+            exit(1);
+        }
+
+        fd_idx = 1;
+        for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next )
+        {
+            switch ( pinfo->con_status )
+            {
+            case CONSTAT_LISTENING:
+                if ( ((polls[fd_idx].revents & POLLIN) != 0) )
+                    (void)make_consock_connected(pinfo);
+                break;
+            case CONSTAT_CONNECTED:
+                if ( ((polls[fd_idx].revents & POLLOUT) != 0) )
+                    do_consock_write(pinfo);
+                if ( ((polls[fd_idx].revents & POLLIN) != 0) )
+                    do_consock_read(pinfo);
+                break;
+            }
+            fd_idx++;
+        }
+
+        while ( (bytes = read(evt_fd, buf, sizeof(buf))) == -1 )
+        {
+            if ( errno == EINTR )
+                continue;
+            if ( errno == EAGAIN )
+            {
+                bytes = 0;
+                break;
+            }
+            SYS_ERROR("Unexpected error while reading '%s'.", EVTCHN_DEV_NAME);
+            exit(1);
+        }
+        
+        if ( bytes == 0 )
             continue;
-        SYS_ERROR("Unexpected error reading '%s'.", EVTCHN_DEV_NAME);
-        exit(1);
+
+        if ( (bytes & 1) != 0 )
+        {
+            ERROR("Bad read length (%d bytes) from '%s'.",
+                  bytes, EVTCHN_DEV_NAME);
+            exit(1);
+        }
+        
+        batch = bytes / sizeof(u16);
+        for ( i = 0; i < batch; i++ )
+        {
+            port = buf[i] & PORTIDX_MASK;
+            
+            if ( buf[i] & PORT_DISCONNECT )
+            {
+                DPRINTF("Disconnect on port %d.", port);
+                (void)handle_channel_exception(port);
+                continue;
+            }
+            
+            if ( portinfo[port].interface == NULL )
+            {
+                DPRINTF("Unexpected notification on port %d.", port);
+                if ( !handle_channel_exception(port) )
+                    continue;
+            }
+            
+            process_channel(port);
+        }
+    }
+
+    (void)xc_interface_close(xc_fd);
+    (void)close(mem_fd);
+    (void)close(evt_fd);
+
+    return 0;
+}
+
+
+/* Returns non-zero if console is listening on exit. */
+static int make_consock_listener(portinfo_t *pinfo)
+{
+    int reuseaddr_flag = 1;
+    struct linger linger;
+    int tcp_port = 9600 + PORT(pinfo);
+    int fd, flags;
+    struct sockaddr_in sa;
+
+    if ( pinfo->con_status == CONSTAT_LISTENING )
+        return 1;
+
+    if ( pinfo->con_status == CONSTAT_CONNECTED )
+    {
+        (void)close(pinfo->con_fd);
+        pinfo->con_status = CONSTAT_CLOSED;
     }
 
-    if ( (bytes == 0) || ((bytes & 1) != 0) )
+    if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
     {
-        ERROR("Short or bad read length (%d bytes) from '%s'.",
-              bytes, EVTCHN_DEV_NAME);
-        exit(1);
+        SYS_ERROR("Could not create TCP socket.");
+        return 0;
+    }
+
+    linger.l_onoff = 0;
+    if ( (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
+                     &reuseaddr_flag, sizeof(int)) != 0) ||
+         (setsockopt(fd, SOL_SOCKET, SO_LINGER, 
+                     &linger, sizeof(linger)) != 0) )
+    {
+        SYS_ERROR("Could not enable immediate reuse of socket port.");
+        close(fd);
+        return 0;
+    }
+
+    sa.sin_family      = AF_INET;
+    sa.sin_addr.s_addr = htonl(INADDR_ANY);
+    sa.sin_port        = htons(tcp_port);
+    if ( bind(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0 )
+    {
+        SYS_ERROR("Unable to bind to console port %d.", tcp_port);
+        close(fd);
+        return 0;
+    }
+
+    if ( listen(fd, 5) != 0 )
+    {
+        SYS_ERROR("Unable to listen on console port %d.", tcp_port);
+        close(fd);
+        return 0;
+    }
+
+    if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
+         (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) )
+    {
+        SYS_ERROR("Unable to set non-blocking status for console listener.");
+        close(fd);
+        return 0;
+    }
+
+    pinfo->con_fd     = fd;
+    pinfo->con_status = CONSTAT_LISTENING;
+    return 1;
+}
+
+/* Returns non-zero if console is connected on exit. */
+static int make_consock_connected(portinfo_t *pinfo)
+{
+    int fd, flags, sa_len;
+    struct linger linger;
+    struct sockaddr_in sa;
+
+    if ( pinfo->con_status == CONSTAT_CONNECTED )
+        return 1;
+
+    if ( pinfo->con_status == CONSTAT_CLOSED )
+        return 0;
+
+    if ( (fd = accept(pinfo->con_fd, (struct sockaddr *)&sa, &sa_len)) == -1 )
+        return 0;
+
+    linger.l_onoff = 0;
+    if ( setsockopt(fd, SOL_SOCKET, SO_LINGER, 
+                    &linger, sizeof(linger)) != 0 )
+    {
+        SYS_ERROR("Could not enable immediate socket death.");
+        close(fd);
+        return 0;
     }
 
-    chunk = bytes / 2;
-    for ( i = 0; i < chunk; i++ )
+    if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
+         (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) )
     {
-        port = buf[i] & PORTIDX_MASK;
-        if ( buf[i] & PORT_DISCONNECT )
+        SYS_ERROR("Unable to set non-blocking status on socket.");
+        close(fd);
+        return 0;
+    }
+
+    (void)close(pinfo->con_fd);
+
+    pinfo->con_fd     = fd;
+    pinfo->con_status = CONSTAT_CONNECTED;
+    return 1;
+}
+
+
+static void make_consock_closed(portinfo_t *pinfo)
+{
+    if ( pinfo->con_status != CONSTAT_CLOSED )
+        (void)close(pinfo->con_fd);
+    pinfo->con_status = CONSTAT_CLOSED;
+}
+
+
+static void do_consock_read(portinfo_t *pinfo)
+{
+    char buf[1024];
+    int  idx, bytes, rc, was_empty = TX_EMPTY(pinfo);
+
+    while ( (rc = read(pinfo->con_fd, &buf, sizeof(buf))) > 0 )
+    {
+        idx = 0;
+        while ( (rc != 0) && !TX_FULL(pinfo) )
         {
-            if ( portinfo[port].comms == NULL )
-                continue;
-            unmap_comms(memfd, portinfo[port].comms);
-            portinfo[port].comms = NULL;
-            (void)write(fd, &buf[i], sizeof(u16));
-            (void)xc_evtchn_close(xch, DOMID_SELF, port);
+            bytes = rc;
+            /* Clip copy to ring-buffer wrap. */
+            if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp)) )
+                bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp);
+            /* Clip copy to ring-buffer overflow. */
+            if ( bytes > (CONBUFSZ - (pinfo->txp - pinfo->txc)) )
+                bytes = CONBUFSZ - (pinfo->txp - pinfo->txc);
+            memcpy(&pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txp)],
+                   &buf[idx], bytes);
+            pinfo->txp += bytes;
+            idx        += bytes;
+            rc         -= bytes;
         }
-        else
+    }
+
+    if ( (rc == 0) || (errno != EAGAIN) )
+    {
+        DPRINTF("Console client has disconnected.");
+        if ( !make_consock_listener(pinfo) )
         {
-            if ( portinfo[port].comms == NULL )
-            {
-                xc_dominfo_t info;
-                xc_evtchn_status(xch, DOMID_SELF, port, 
-                                 &domid, &portid, &status);
-
-                if ( (status == EVTCHNSTAT_closed) ||
-                     ((status == EVTCHNSTAT_disconnected) && (portid == 0)) )
-                {
-                    /* Cleanup sanity: we'll be the grim reaper. */
-                    (void)write(fd, &buf[i], sizeof(u16)); /* PORT_NORMAL */
-                    buf[i] |= PORT_DISCONNECT;
-                    (void)write(fd, &buf[i], sizeof(u16)); /* PORT_DISCON */
-                    continue;
-                }
+            ERROR("Could not revert console %d to listener status.",
+                  PORT(pinfo));
+            exit(1);
+        }
+    }
 
-                /* We only deal with initial ports (id == 0). */
-                if ( portid != 0 )
-                    continue;
+    if ( was_empty && !TX_EMPTY(pinfo) )
+    {
+        /* There is now data to transmit to guest. Kickstart the pipeline. */
+        if ( process_evtchn_writes(pinfo) )
+            (void)xc_evtchn_send(xc_fd, PORT(pinfo));
+    }
+}
 
-                xc_domain_getinfo(xch, domid, 1, &info);
-                portinfo[port].comms = 
-                    map_comms(memfd, info.shared_info_frame);
-                portinfo[port].dom = domid;
-                portinfo[port].tx_req_cons  = 0;
-                portinfo[port].tx_resp_prod = 0;
-                portinfo[port].rx_req_cons  = 0;
-                portinfo[port].rx_resp_prod = 0;
-            }
+static void do_consock_write(portinfo_t *pinfo)
+{
+    int bytes, rc;
+
+    while ( !RX_EMPTY(pinfo) )
+    {
+        /* Clip transfer to ring-buffer wrap. */
+        bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxc);
+        /* Clip transfer to ring-buffer overflow. */
+        if ( bytes > (pinfo->rxp - pinfo->rxc) )
+            bytes = pinfo->rxp - pinfo->rxc;
+        rc = write(pinfo->con_fd, 
+                   &pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxc)], 
+                   bytes);
+        if ( rc <= 0 )
+            return; /* Nothing to do. Errors cleaned up in reader code. */
+        pinfo->rxc += rc;
+    }
+}
+
+static int process_evtchn_reads(portinfo_t *pinfo)
+{
+    CONTROL_RING_IDX c;
+    control_if_t    *cif = pinfo->interface;
+    control_msg_t   *cmsg;
+    unsigned int     clen, idx, len, bytes;
+
+    for ( c = pinfo->tx_req_cons; 
+          (c != cif->tx_req_prod) && 
+              ((c-pinfo->tx_resp_prod) != CONTROL_RING_SIZE);
+          c++ )
+    {
+        cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
+
+        if ( (clen = cmsg->length) > sizeof(cmsg->msg) )
+            clen = sizeof(cmsg->msg);
 
-            do {
-                xc_evtchn_send(xch, port);
-                write(fd, &buf[i], sizeof(u16));
-            } while ( 0 );
+        if ( (cmsg->cmd_type == CMD_CONSOLE) &&
+             (cmsg->cmd_subtype == CMD_CONSOLE_DATA) )
+        {
+            idx = 0;
+            len = cmsg->length;
+            while ( (len != 0) && !RX_FULL(pinfo) )
+            {
+                bytes = len;
+                /* Clip copy to ring-buffer wrap. */
+                if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp)) )
+                    bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp);
+                /* Clip copy to ring-buffer overflow. */
+                if ( bytes > (CONBUFSZ - (pinfo->rxp - pinfo->rxc)) )
+                    bytes = CONBUFSZ - (pinfo->rxp - pinfo->rxc);
+                memcpy(&pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxp)],
+                       &cmsg->msg[idx], bytes);
+                pinfo->rxp += bytes;
+                idx += bytes;
+                len -= bytes;
+            }
         }
+
+        /* Prepare response. No payload; msg type and id same as request. */
+        cmsg->length = 0;
+    }
+
+    if ( c != pinfo->tx_req_cons )
+    {
+        /* Update private indexes. */
+        pinfo->tx_resp_prod = c;
+        pinfo->tx_req_cons  = c;
+        /* Queue responses and send a notification to the guest OS. */
+        cif->tx_resp_prod   = c;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int process_evtchn_writes(portinfo_t *pinfo)
+{
+    CONTROL_RING_IDX p, rx_resp_prod;
+    control_if_t    *cif = pinfo->interface;
+    control_msg_t   *cmsg;
+    unsigned int     bytes;
+
+    /* Validate the rx-response producer, an dupdate our consumer if okay. */
+    rx_resp_prod = cif->rx_resp_prod;
+    if ( (pinfo->rx_resp_cons != rx_resp_prod) &&
+         ((pinfo->rx_req_prod - rx_resp_prod) <= CONTROL_RING_SIZE) &&
+         ((rx_resp_prod - pinfo->rx_resp_cons) <= CONTROL_RING_SIZE) )
+        pinfo->rx_resp_cons = cif->rx_resp_prod;
+
+    for ( p = pinfo->rx_req_prod;
+          (p-pinfo->rx_resp_cons) != CONTROL_RING_SIZE;
+          p++ )
+    {
+        if ( TX_EMPTY(pinfo) )
+            break;
+        cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
+        bytes = sizeof(cmsg->msg);
+        /* Clip transfer to ring-buffer wrap. */
+        if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc)) )
+            bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc);
+        /* Clip transfer to ring-buffer overflow. */
+        if ( bytes > (pinfo->txp - pinfo->txc) )
+            bytes = pinfo->txp - pinfo->txc;
+        cmsg->cmd_type    = CMD_CONSOLE;
+        cmsg->cmd_subtype = CMD_CONSOLE_DATA;
+        cmsg->id          = 0xaa;
+        cmsg->length      = bytes;
+        memcpy(&cmsg->msg[0], 
+               &pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txc)], 
+               bytes);
+        pinfo->txc += bytes;
     }
 
-    (void)xc_interface_close(xch);
-    (void)close(memfd);
-    (void)close(fd);
+    if ( p != pinfo->rx_req_prod )
+    {
+        pinfo->rx_req_prod  = p;
+        cif->rx_req_prod    = p;
+        return 1;
+    }
 
     return 0;
 }
index 84ef14cf8fe5b722cb5bfcbc86ff886714569f68..15dadf35b7dbc07df3162a7e5273938602a82ff6 100644 (file)
@@ -327,3 +327,79 @@ long do_update_descriptor(
     put_page(page);
     return ret;
 }
+
+#ifdef MEMORY_GUARD
+
+void *memguard_init(void *heap_start)
+{
+    l1_pgentry_t *l1;
+    int i, j;
+
+    /* Round the allocation pointer up to a page boundary. */
+    heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) & 
+                          PAGE_MASK);
+
+    /* Memory guarding is incompatible with super pages. */
+    for ( i = 0; i < (MAX_MONITOR_ADDRESS >> L2_PAGETABLE_SHIFT); i++ )
+    {
+        l1 = (l1_pgentry_t *)heap_start;
+        heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE);
+        for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
+            l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
+                                   (j << L1_PAGETABLE_SHIFT) | 
+                                  __PAGE_HYPERVISOR);
+        idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
+            mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
+    }
+
+    return heap_start;
+}
+
+static void __memguard_change_range(void *p, unsigned long l, int guard)
+{
+    l1_pgentry_t *l1;
+    l2_pgentry_t *l2;
+    unsigned long _p = (unsigned long)p;
+    unsigned long _l = (unsigned long)l;
+
+    /* Ensure we are dealing with a page-aligned whole number of pages. */
+    ASSERT((_p&PAGE_MASK) != 0);
+    ASSERT((_l&PAGE_MASK) != 0);
+    ASSERT((_p&~PAGE_MASK) == 0);
+    ASSERT((_l&~PAGE_MASK) == 0);
+
+    while ( _l != 0 )
+    {
+        l2  = &idle_pg_table[l2_table_offset(_p)];
+        l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
+        if ( guard )
+            *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT);
+        else
+            *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) | _PAGE_PRESENT);
+        _p += PAGE_SIZE;
+        _l -= PAGE_SIZE;
+    }
+}
+
+void memguard_guard_range(void *p, unsigned long l)
+{
+    __memguard_change_range(p, l, 1);
+    local_flush_tlb();
+}
+
+void memguard_unguard_range(void *p, unsigned long l)
+{
+    __memguard_change_range(p, l, 0);
+}
+
+int memguard_is_guarded(void *p)
+{
+    l1_pgentry_t *l1;
+    l2_pgentry_t *l2;
+    unsigned long _p = (unsigned long)p;
+    l2  = &idle_pg_table[l2_table_offset(_p)];
+    l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
+    return !(l1_pgentry_val(*l1) & _PAGE_PRESENT);
+}
+
+#endif
index 8359fd086c32ed8b153a8a3aa38f7c83b8e41a03..ef3626ccf5e022889c0681bc3fd0ad78c96eaa08 100644 (file)
@@ -323,29 +323,9 @@ void __init start_of_day(void)
     extern int do_timer_lists_from_pit;
     unsigned long low_mem_size;
     
-#ifdef STACK_GUARD
-    extern unsigned long cpu0_stack[];
-    l1_pgentry_t *l1;
-    l2_pgentry_t *l2;
-    int i, j;
-
-    /* When stack-guarding, Xen's heap cannot be mapped by super pages. */
-    for ( i = 0; i < (MAX_MONITOR_ADDRESS >> L2_PAGETABLE_SHIFT); i++ )
-    {
-        l1 = (l1_pgentry_t *)get_free_page(GFP_KERNEL);
-        for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
-            l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
-                                   (j << L1_PAGETABLE_SHIFT) | 
-                                   PAGE_HYPERVISOR);
-        idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
-            mk_l2_pgentry(virt_to_phys(l1) | PAGE_HYPERVISOR);
-    }
-
     /* Unmap the first page of CPU0's stack. */
-    l2  = &idle_pg_table[l2_table_offset(virt_to_phys(cpu0_stack))];
-    l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(virt_to_phys(cpu0_stack));
-    *l1 = mk_l1_pgentry(0);
-#endif
+    extern unsigned long cpu0_stack[];
+    memguard_guard_range(cpu0_stack, PAGE_SIZE);
 
     if ( opt_watchdog ) 
         nmi_watchdog = NMI_LOCAL_APIC;
index 0812c0cdb1e4a596e5f53a79ad358414a26ee39c..dcfe8313d320dc5bee823b91d74fed98283b1d9e 100644 (file)
@@ -691,16 +691,11 @@ static void __init do_boot_cpu (int apicid)
     printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
 
     stack = __pa(__get_free_pages(GFP_KERNEL, 1));
-#ifdef STACK_GUARD
-    {
-        /* Unmap the first page of the new CPU0's stack. */
-        l2_pgentry_t *l2  = &idle_pg_table[l2_table_offset(stack)];
-        l1_pgentry_t *l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(stack);
-        *l1 = mk_l1_pgentry(0);
-    }
-#endif
     stack_start.esp = stack + STACK_SIZE - STACK_RESERVED;
 
+    /* Debug build: detect stack overflow by setting up a guard page. */
+    memguard_guard_range(__va(stack), PAGE_SIZE);
+
     /*
      * This grunge runs the startup process for
      * the targeted processor.
index 3f8308347c5390f50d0c1f3938c5cdf27462f1f2..31a59637c59010aaa438ddfdd4ac4457665a1226 100644 (file)
@@ -370,6 +370,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
             page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
             printk(" *pte = %08lx\n", page);
         }
+#ifdef MEMORY_GUARD
+        if ( !(error_code & 1) )
+            printk(" -- POSSIBLY AN ACCESS TO FREED MEMORY? --\n");
+#endif
     }
 
     show_registers(regs);
index a6449d6d7ea0cc7fea455e89a615e1bd64d56c27..6983649c9e5d6e6950df8210f8a11574b365093e 100644 (file)
@@ -230,9 +230,6 @@ static long __event_channel_close(struct task_struct *p1, int port1)
     guest_event_notify(cpu_mask);
 
  out:
-    spin_unlock(&p1->event_channel_lock);
-    put_task_struct(p1);
-
     if ( p2 != NULL )
     {
         if ( p1 != p2 )
@@ -240,6 +237,8 @@ static long __event_channel_close(struct task_struct *p1, int port1)
         put_task_struct(p2);
     }
     
+    spin_unlock(&p1->event_channel_lock);
+
     return rc;
 }
 
index 9db60eca822247699a9d0b32ac07600579674367..a906786c428a9e9521830259c459de0e8c376828 100644 (file)
@@ -110,6 +110,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi)
     unsigned long max_page;
     unsigned char *cmdline, *p;
     module_t *mod;
+    void *heap_start;
     int i;
 
     /* Parse the command-line options. */
@@ -222,7 +223,9 @@ void cmain(unsigned long magic, multiboot_info_t *mbi)
     printk("Initialised all memory on a %luMB machine\n",
            max_page >> (20-PAGE_SHIFT));
 
-    init_page_allocator(__pa(&_end), MAX_MONITOR_ADDRESS);
+    heap_start = memguard_init(&_end);
+
+    init_page_allocator(__pa(heap_start), MAX_MONITOR_ADDRESS);
  
     /* Initialise the slab allocator. */
     kmem_cache_init();
@@ -460,85 +463,6 @@ void printf(const char *fmt, ...)
 }
 
 
-unsigned short compute_cksum(unsigned short *buf, int count)
-{
-    unsigned long sum = 0;
-    while ( count-- )
-        sum += *buf++;
-    while ( sum >> 16 )
-       sum = (sum & 0xffff) + (sum >> 16);
-    return (unsigned short) ~sum;
-}
-
-
-/*
- * Function written by ek247. Exports console output from all domains upwards 
- * to domain0, by stuffing it into a fake network packet.
- */
-int console_export(char *str, int len)
-{
-    struct sk_buff *skb;
-    struct iphdr *iph = NULL;  
-    struct udphdr *udph = NULL; 
-    struct ethhdr *ethh = NULL; 
-    int hdr_size = sizeof(struct iphdr) + sizeof(struct udphdr); 
-    u8 *skb_data;
-
-    skb = dev_alloc_skb(sizeof(struct ethhdr) + 
-                                   hdr_size + len + 20);
-    if ( skb == NULL ) return 0;
-
-    skb->dev = the_dev;
-    skb_data = (u8 *)map_domain_mem((skb->pf - frame_table) << PAGE_SHIFT);
-    skb_reserve(skb, 2);
-
-    /* Get a pointer to each header. */
-    ethh = (struct ethhdr *) 
-        (skb_data + (skb->data - skb->head));
-    iph  = (struct iphdr *)(ethh + 1);
-    udph = (struct udphdr *)(iph + 1); 
-
-    skb_reserve(skb, sizeof(struct ethhdr)); 
-    skb_put(skb, hdr_size +  len); 
-
-    /* Build IP header. */
-    iph->version = 4;
-    iph->ihl     = 5;
-    iph->tos    = 0;
-    iph->tot_len = htons(hdr_size + len);
-    iph->id      = 0xdead;
-    iph->frag_off= 0;
-    iph->ttl     = 255;
-    iph->protocol= 17;
-    iph->daddr   = htonl(0xa9fe0100);  /* 169.254.1.0 */
-    iph->saddr   = htonl(0xa9fefeff);  /* 169.254.254.255 */
-    iph->check  = 0;
-    iph->check   = compute_cksum((__u16 *)iph, sizeof(struct iphdr)/2); 
-
-    /* Build UDP header. */
-    udph->source = htons(current->domain);
-    udph->dest   = htons(666);
-    udph->len    = htons(sizeof(struct udphdr) + len);
-    udph->check  = 0;
-
-    /* Build the UDP payload. */
-    memcpy((char *)(udph + 1), str, len); 
-
-    /* Fix Ethernet header. */
-    memset(ethh->h_source, 0, ETH_ALEN);
-    memset(ethh->h_dest,   0, ETH_ALEN);
-    ethh->h_proto = htons(ETH_P_IP);
-    skb->mac.ethernet= (struct ethhdr *)ethh;
-
-    unmap_domain_mem(skb_data);
-    
-    skb->dst_vif = find_net_vif(0, 0);
-    (void)netif_rx(skb);
-
-    return 1;
-}
-
-
 long do_console_write(char *str, unsigned int count)
 {
 #define SIZEOF_BUF 256
@@ -583,9 +507,6 @@ long do_console_write(char *str, unsigned int count)
         __putstr(line_header);
         __putstr(single_line);
         spin_unlock_irqrestore(&console_lock, flags);
-
-        if ( current->domain != 0 )
-            console_export(single_line, j);
     }
 
     return 0;
@@ -648,28 +569,3 @@ long do_ni_syscall(void)
     /* No-op syscall. */
     return -ENOSYS;
 }
-
-
-/*
- * GRAVEYARD
- */
-#if 0
-    if ( (mbi->flags & (1<<6)) )
-    {
-        memory_map_t *mmap = (memory_map_t *)mbi->mmap_addr;
-        struct e820entry *e820 = E820_MAP;
-
-        while ( (unsigned long)mmap < (mbi->mmap_addr + mbi->mmap_length) )
-        {
-            e820->addr_lo = mmap->base_addr_low;
-            e820->addr_hi = mmap->base_addr_high;
-            e820->size_lo = mmap->length_low;
-            e820->size_hi = mmap->length_high;
-            e820->type    = mmap->type;
-            e820++;
-            mmap = (memory_map_t *) 
-                ((unsigned long)mmap + mmap->size + sizeof (mmap->size));
-        }
-    }
-#endif
-
index ca609438e04e36bf0474828528710a0b00370994..db9d2ba9ea15936f746af58fc4cc7bad97eb414a 100644 (file)
@@ -118,11 +118,90 @@ struct chunk_tail_st {
 #define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT)
 static chunk_head_t *free_head[FREELIST_SIZE];
 static chunk_head_t  free_tail[FREELIST_SIZE];
-#define FREELIST_EMPTY(_l) ((_l)->next == NULL)
+#define FREELIST_EMPTY(_i) (free_head[_i] == &free_tail[i])
 
 #define round_pgdown(_p)  ((_p)&PAGE_MASK)
 #define round_pgup(_p)    (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
 
+#ifdef MEMORY_GUARD
+
+/*
+ * Debug build: free memory chunks are made inaccessible.
+ */
+
+/* Make order-'o' pages inaccessible, from address 'p'. */
+static inline void GUARD(void *p, int o)
+{
+    p = (void *)((unsigned long)p&PAGE_MASK);
+    if ( p > (void *)&_end ) /* careful not to protect the 'free_tail' array */
+        memguard_guard_range(p, (1<<(o+PAGE_SHIFT)));
+}
+
+/* Make order-'o' pages accessible, from address 'p'. */
+static inline void UNGUARD(void *p, int o)
+{
+    p = (void *)((unsigned long)p&PAGE_MASK);
+    if ( p > (void *)&_end ) /* careful not to protect the 'free_tail' array */
+        memguard_unguard_range(p, (1<<(o+PAGE_SHIFT)));
+}
+
+/* Safe form of 'ch->level'. */
+static inline int HEAD_LEVEL(chunk_head_t *ch)
+{
+    int l;
+    ASSERT(memguard_is_guarded(ch));
+    UNGUARD(ch, 0);
+    l = ch->level;
+    GUARD(ch, 0);
+    return l;
+}
+
+/* Safe form of 'ct->level'. */
+static inline int TAIL_LEVEL(chunk_tail_t *ct)
+{
+    int l;
+    ASSERT(memguard_is_guarded(ct));
+    UNGUARD(ct, 0);
+    l = ct->level;
+    GUARD(ct, 0);
+    return l;
+}
+
+/* Safe form of '*ch->pprev = l'. */
+static inline void UPDATE_PREV_FORWARDLINK(chunk_head_t *ch, chunk_head_t *l)
+{
+    ASSERT(((void *)ch->pprev < (void *)&_end) || 
+           memguard_is_guarded(ch->pprev));
+    UNGUARD(ch->pprev, 0);
+    *ch->pprev = l;
+    GUARD(ch->pprev, 0);
+}
+
+/* Safe form of 'ch->next->pprev = l'. */
+static inline void UPDATE_NEXT_BACKLINK(chunk_head_t *ch, chunk_head_t **l)
+{
+    ASSERT(((void *)ch->next < (void *)&_end) || 
+           memguard_is_guarded(ch->next));
+    UNGUARD(ch->next, 0);
+    ch->next->pprev = l;
+    GUARD(ch->next, 0);
+}
+
+#else
+
+/*
+ * Non-debug build: free memory chunks are not made inaccessible.
+ */
+
+#define GUARD(_p,_o) ((void)0)
+#define UNGUARD(_p,_o) ((void)0)
+#define HEAD_LEVEL(_ch) ((_ch)->level)
+#define TAIL_LEVEL(_ct) ((_ct)->level)
+#define UPDATE_PREV_FORWARDLINK(_ch,_link) (*(_ch)->pprev = (_link))
+#define UPDATE_NEXT_BACKLINK(_ch,_link) ((_ch)->next->pprev = (_link))
+
+#endif
+
 
 /*
  * Initialise allocator, placing addresses [@min,@max] in free pool.
@@ -131,7 +210,7 @@ static chunk_head_t  free_tail[FREELIST_SIZE];
 void __init init_page_allocator(unsigned long min, unsigned long max)
 {
     int i;
-    unsigned long range, bitmap_size;
+    unsigned long range, bitmap_size, p, remaining;
     chunk_head_t *ch;
     chunk_tail_t *ct;
 
@@ -161,19 +240,21 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
     min += PAGE_OFFSET;
     max += PAGE_OFFSET;
 
-    while ( range != 0 )
+    p         = min;
+    remaining = range;
+    while ( remaining != 0 )
     {
         /*
-         * Next chunk is limited by alignment of min, but also
-         * must not be bigger than remaining range.
+         * Next chunk is limited by alignment of p, but also must not be bigger
+         * than remaining bytes.
          */
-        for ( i = PAGE_SHIFT; (1<<(i+1)) <= range; i++ )
-            if ( min & (1<<i) ) break;
+        for ( i = PAGE_SHIFT; (1<<(i+1)) <= remaining; i++ )
+            if ( p & (1<<i) ) break;
 
-        ch = (chunk_head_t *)min;
-        min   += (1<<i);
-        range -= (1<<i);
-        ct = (chunk_tail_t *)min-1;
+        ch = (chunk_head_t *)p;
+        p         += (1<<i);
+        remaining -= (1<<i);
+        ct = (chunk_tail_t *)p - 1;
         i -= PAGE_SHIFT;
         ch->level       = i;
         ch->next        = free_head[i];
@@ -182,20 +263,8 @@ void __init init_page_allocator(unsigned long min, unsigned long max)
         free_head[i]    = ch;
         ct->level       = i;
     }
-}
 
-
-/* Release a PHYSICAL address range to the allocator. */
-void release_bytes_to_allocator(unsigned long min, unsigned long max)
-{
-    min = round_pgup  (min);
-    max = round_pgdown(max);
-
-    while ( min < max )
-    {
-        __free_pages(min+PAGE_OFFSET, 0);
-        min += PAGE_SIZE;
-    }
+    memguard_guard_range((void *)min, range);
 }
 
 
@@ -212,7 +281,7 @@ retry:
 
     /* Find smallest order which can satisfy the request. */
     for ( i = order; i < FREELIST_SIZE; i++ ) {
-       if ( !FREELIST_EMPTY(free_head[i]) ) 
+       if ( !FREELIST_EMPTY(i) ) 
            break;
     }
 
@@ -220,8 +289,10 @@ retry:
  
     /* Unlink a chunk. */
     alloc_ch = free_head[i];
+    UNGUARD(alloc_ch, i);
     free_head[i] = alloc_ch->next;
-    alloc_ch->next->pprev = alloc_ch->pprev;
+    /* alloc_ch->next->pprev = alloc_ch->pprev */
+    UPDATE_NEXT_BACKLINK(alloc_ch, alloc_ch->pprev);
 
     /* We may have to break the chunk a number of times. */
     while ( i != order )
@@ -238,14 +309,21 @@ retry:
         spare_ct->level = i;
 
         /* Link in the spare chunk. */
-        spare_ch->next->pprev = &spare_ch->next;
+        /* spare_ch->next->pprev = &spare_ch->next */
+        UPDATE_NEXT_BACKLINK(spare_ch, &spare_ch->next);
         free_head[i] = spare_ch;
+        GUARD(spare_ch, i);
     }
     
     map_alloc(__pa(alloc_ch)>>PAGE_SHIFT, 1<<order);
 
     spin_unlock_irqrestore(&alloc_lock, flags);
 
+#ifdef MEMORY_GUARD
+    /* Now we blast the contents of the block. */
+    memset(alloc_ch, 0x55, 1 << (order + PAGE_SHIFT));
+#endif
+
     return((unsigned long)alloc_ch);
 
  no_memory:
@@ -274,6 +352,17 @@ void __free_pages(unsigned long p, int order)
 
     spin_lock_irqsave(&alloc_lock, flags);
 
+#ifdef MEMORY_GUARD
+    /* Check that the block isn't already freed. */
+    if ( !allocated_in_map(pagenr) )
+        BUG();
+    /* Check that the block isn't already guarded. */
+    if ( __put_user(1, (int*)p) )
+        BUG();
+    /* Now we blast the contents of the block. */
+    memset((void *)p, 0xaa, size);
+#endif
+
     map_free(pagenr, 1<<order);
     
     /* Merge chunks as far as possible. */
@@ -282,23 +371,30 @@ void __free_pages(unsigned long p, int order)
         if ( (p & size) )
         {
             /* Merge with predecessor block? */
-            if ( allocated_in_map(pagenr-1) ) break;
+            if ( allocated_in_map(pagenr-1) )
+                break;
             ct = (chunk_tail_t *)p - 1;
-            if ( ct->level != order ) break;
+            if ( TAIL_LEVEL(ct) != order )
+                break;
             ch = (chunk_head_t *)(p - size);
             p -= size;
         }
         else
         {
             /* Merge with successor block? */
-            if ( allocated_in_map(pagenr+(1<<order)) ) break;
+            if ( allocated_in_map(pagenr+(1<<order)) )
+                break;
             ch = (chunk_head_t *)(p + size);
-            if ( ch->level != order ) break;
+            if ( HEAD_LEVEL(ch) != order )
+                break;
         }
         
         /* Okay, unlink the neighbour. */
-        *ch->pprev = ch->next;
-        ch->next->pprev = ch->pprev;
+        UNGUARD(ch, order);
+        /* *ch->pprev = ch->next */
+        UPDATE_PREV_FORWARDLINK(ch, ch->next);
+        /* ch->next->pprev = ch->pprev */
+        UPDATE_NEXT_BACKLINK(ch, ch->pprev);
 
         order++;
         size <<= 1;
@@ -311,8 +407,10 @@ void __free_pages(unsigned long p, int order)
     ch->level = order;
     ch->pprev = &free_head[order];
     ch->next  = free_head[order];
-    ch->next->pprev = &ch->next;
+    /* ch->next->pprev = &ch->next */
+    UPDATE_NEXT_BACKLINK(ch, &ch->next);
     free_head[order] = ch;
+    GUARD(ch, order);
 
     spin_unlock_irqrestore(&alloc_lock, flags);
 }
index c2bcb91c0692ebd07237c61f619045a954233433..5487f15e5aee1e7a814955f92a15d83a56745336 100644 (file)
@@ -165,6 +165,7 @@ int sched_rem_domain(struct task_struct *p)
     do {
         if ( (x = y) == TASK_DYING ) return 0;
     } while ( (y = cmpxchg(&p->state, x, TASK_DYING)) != x );
+    rem_ac_timer(&p->timer);
     return 1;
 }
 
index e8dffa1a2ae40271340077b8bee55750862f3983..bfd99a07258ef92242cdbb1ac9a12becb0c27f32 100644 (file)
 #ifndef NDEBUG
 #define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
                            __FILE__ , __LINE__ , ## _a )
-#define STACK_GUARD
+#define MEMORY_GUARD
 #define TRACE_BUFFER
 #else
 #define DPRINTK(_f, _a...) ((void)0)
index d5c3c5d6cb06cebda7181ced167be16305f3b48b..0774571a73ebe90f9711052bccc0f5dd9b7da5a6 100644 (file)
@@ -36,7 +36,6 @@
  */
 
 void init_page_allocator(unsigned long min, unsigned long max);
-void release_bytes_to_allocator(unsigned long min, unsigned long max);
 unsigned long __get_free_pages(int mask, int order);
 void __free_pages(unsigned long p, int order);
 #define get_free_page(_m) (__get_free_pages((_m),0))
@@ -317,4 +316,16 @@ int do_mmu_update(mmu_update_t *updates, int count);
 #define DEFAULT_GDT_ENTRIES     ((LAST_RESERVED_GDT_ENTRY*8)+7)
 #define DEFAULT_GDT_ADDRESS     ((unsigned long)gdt_table)
 
+#ifdef MEMORY_GUARD
+void *memguard_init(void *heap_start);
+void memguard_guard_range(void *p, unsigned long l);
+void memguard_unguard_range(void *p, unsigned long l);
+int memguard_is_guarded(void *p);
+#else
+#define memguard_init(_s)              (_s)
+#define memguard_guard_range(_p,_l)    ((void)0)
+#define memguard_unguard_range(_p,_l)  ((void)0)
+#define memguard_is_guarded(_p)        (0)
+#endif
+
 #endif /* __XENO_MM_H__ */
index b58b83d29345eb272db053a427317cf45518826d..041f2fc8cd6ecebc32bf9111a5b7bed817e32aab 100644 (file)
@@ -57,9 +57,9 @@ SUBDIRS += arch/xeno/drivers/dom0
 endif
 
 CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
+CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o
 CORE_FILES += arch/xeno/drivers/console/con.o
 CORE_FILES += arch/xeno/drivers/block/blk.o
-CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o
 CORE_FILES += arch/xeno/drivers/network/net.o
 ifdef CONFIG_XENO_PRIV
 CORE_FILES += arch/xeno/drivers/dom0/dom0.o
index b93fe47656e57853579dfd18328826b9c1bbfc96..7aaac28bca36927a8fd8c4c7062513813502a8a1 100644 (file)
@@ -1,5 +1,9 @@
 /******************************************************************************
  * console.c
+ * 
+ * Virtual console driver.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser.
  */
 
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/console.h>
-
+#include <asm/evtchn.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/hypervisor.h>
+#include <asm/hypervisor-ifs/event_channel.h>
+#include <asm/control_if.h>
+
+static spinlock_t xeno_console_lock = SPIN_LOCK_UNLOCKED;
 
 #define XENO_TTY_MINOR 123
 
-/*** Useful function for console debugging -- goes straight to Xen ****/
-asmlinkage int xprintk(const char *fmt, ...)
+/******************** Kernel console driver ********************************/
+
+static void nonpriv_conwrite(const char *s, unsigned int count)
 {
-    va_list args;
-    int printk_len;
-    static char printk_buf[1024];
-    
-    /* Emit the output into the temporary buffer */
-    va_start(args, fmt);
-    printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-    va_end(args);
-    
-    /* Send the processed output directly to Xen. */
-    (void)HYPERVISOR_console_write(printk_buf, printk_len);
+    control_if_t *ctrl_if;
+    evtchn_op_t   evtchn_op;
+    int           src, dst, p;
+    unsigned long flags;
 
-    return 0;
-}
+    ctrl_if = (control_if_t *)((char *)HYPERVISOR_shared_info + 2048);
 
+    spin_lock_irqsave(&xeno_console_lock, flags);
 
+    while ( count != 0 )
+    {
+        /* Wait for the request ring to drain. */
+        while ( ctrl_if->tx_resp_prod != ctrl_if->tx_req_prod )
+            barrier();
+
+        p = MASK_CONTROL_IDX(ctrl_if->tx_req_prod);
+        
+        ctrl_if->tx_ring[p].cmd_type    = CMD_CONSOLE;
+        ctrl_if->tx_ring[p].cmd_subtype = CMD_CONSOLE_DATA;
+        ctrl_if->tx_ring[p].id          = 0xaa;
+        src = dst = 0;
+        while ( (src < count) && (dst < (sizeof(ctrl_if->tx_ring[p].msg)-1)) )
+        {
+            if ( (ctrl_if->tx_ring[p].msg[dst++] = s[src++]) == '\n' )
+                ctrl_if->tx_ring[p].msg[dst++] = '\r';
+        }
+        ctrl_if->tx_ring[p].length = dst;
+        
+        ctrl_if->tx_req_prod++;
+        evtchn_op.cmd = EVTCHNOP_send;
+        evtchn_op.u.send.local_port = 0;
+        (void)HYPERVISOR_event_channel_op(&evtchn_op);
+        
+        s     += src;
+        count -= src;
+    }
 
-/******************** Kernel console driver ********************************/
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
+}
 
-static void xen_console_write(struct console *co, const char *s, unsigned count)
+static void priv_conwrite(const char *s, unsigned int count)
 {
-#define STRLEN 256
-    static char str[STRLEN];
+    static char str[256];
     static int pos = 0;
     int len;
-    
+
     /* We buffer output until we see a newline, or until the buffer is full. */
     while ( count != 0 )
     {
-        len = ((STRLEN - pos) > count) ? count : STRLEN - pos;
+        len = ((sizeof(str) - pos) > count) ? count : sizeof(str) - pos;
         memcpy(str + pos, s, len);
         pos   += len;
         s     += len;
         count -= len;
-        if ( (pos == STRLEN) || (str[pos-1] == '\n') )
+        if ( (pos == sizeof(str)) || (str[pos-1] == '\n') )
         {
             (void)HYPERVISOR_console_write(str, pos);
             pos = 0;
@@ -71,6 +100,15 @@ static void xen_console_write(struct console *co, const char *s, unsigned count)
     }
 }
 
+static void xen_console_write(struct console *co, const char *s, 
+                              unsigned int count)
+{
+    if ( !(start_info.flags & SIF_INITDOMAIN) )
+        nonpriv_conwrite(s, count);
+    else
+        priv_conwrite(s, count);
+}
+
 static kdev_t xen_console_device(struct console *c)
 {
     /*
@@ -92,34 +130,184 @@ static struct console xen_console_info = {
 
 void xen_console_init(void)
 {
-  xprintk("xen_console_init\n");
-  register_console(&xen_console_info);
+    register_console(&xen_console_info);
 }
 
 
-/******************** Initial /dev/console *********************************/
+/*** Useful function for console debugging -- goes straight to Xen ****/
+asmlinkage int xprintk(const char *fmt, ...)
+{
+    va_list args;
+    int printk_len;
+    static char printk_buf[1024];
+    
+    /* Emit the output into the temporary buffer */
+    va_start(args, fmt);
+    printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+    va_end(args);
+    
+    /* Send the processed output directly to Xen. */
+    xen_console_write(NULL, printk_buf, printk_len);
+
+    return 0;
+}
+
 
+/******************** User-space console driver (/dev/console) ************/
 
 static struct tty_driver xeno_console_driver;
 static int xeno_console_refcount;
 static struct tty_struct *xeno_console_table[1];
 static struct termios *xeno_console_termios[1];
 static struct termios *xeno_console_termios_locked[1];
+static struct tty_struct *xeno_console_tty;
+static int xeno_console_use_count;
+
+#define WBUF_SIZE     1024
+#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
+static char wbuf[WBUF_SIZE], x_char;
+static unsigned int wc, wp; /* write_cons, write_prod */
+
+static void __do_console_io(void)
+{
+    control_if_t    *ctrl_if;
+    control_msg_t   *msg;
+    evtchn_op_t      evtchn_op;
+    CONTROL_RING_IDX c;
+    int              i, len, work_done = 0;
+
+    if ( (start_info.flags & SIF_INITDOMAIN) || (xeno_console_tty == NULL) )
+        return;
+
+    /* Acknowledge the notification. */
+    evtchn_clear_port(0);
+
+    ctrl_if = (control_if_t *)((char *)HYPERVISOR_shared_info + 2048);
+    
+    /* Receive work. */
+    for ( c = ctrl_if->rx_resp_prod; c != ctrl_if->rx_req_prod; c++ )
+    {
+        msg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(c)];
+        if ( (msg->cmd_type == CMD_CONSOLE) &&
+             (msg->cmd_subtype == CMD_CONSOLE_DATA) )
+        {
+            for ( i = 0; i < msg->length; i++ )
+                tty_insert_flip_char(xeno_console_tty, msg->msg[i], 0);
+        }
+        msg->length = 0;
+    }
+    if ( ctrl_if->rx_resp_prod != c )
+    {
+        ctrl_if->rx_resp_prod = c;
+        work_done = 1;
+        tty_flip_buffer_push(xeno_console_tty);
+    }
+    
+    /* Transmit work. */
+    for ( c = ctrl_if->tx_req_prod; 
+          (c - ctrl_if->tx_resp_prod) != CONTROL_RING_SIZE; 
+          c++ )
+    {
+        if ( (wc == wp) && (x_char == 0) )
+            break;
+        msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(c)];
+        msg->cmd_type    = CMD_CONSOLE;
+        msg->cmd_subtype = CMD_CONSOLE_DATA;
+        msg->id          = 0xaa;
+        len = 0;
+        if ( x_char != 0 ) /* Handle XON/XOFF urgently. */
+        {
+            msg->msg[len++] = x_char;
+            x_char = 0;
+        }
+        while ( (len < sizeof(msg->msg)) && (wc != wp) )
+            msg->msg[len++] = wbuf[WBUF_MASK(wc++)];
+        msg->length = len;
+    }
+    if ( ctrl_if->tx_req_prod != c )
+    {
+        ctrl_if->tx_req_prod = c;
+        work_done = 1;
+    }
+        
+    if ( work_done )
+    {
+        /* Send a notification to the controller. */
+        evtchn_op.cmd = EVTCHNOP_send;
+        evtchn_op.u.send.local_port = 0;
+        (void)HYPERVISOR_event_channel_op(&evtchn_op);
+
+        /* There might be something for waiters to do. */
+        if ( xeno_console_tty != NULL )
+            wake_up_interruptible(&xeno_console_tty->write_wait);
+    }
+}
+
+static void control_event(unsigned int port)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&xeno_console_lock, flags);
+    __do_console_io();
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
+}
 
 static int xeno_console_write_room(struct tty_struct *tty)
 {
-    return INT_MAX;
+    return WBUF_SIZE - (wp - wc);
 }
 
 static int xeno_console_chars_in_buffer(struct tty_struct *tty)
 {
-    return 0;
+    return wp - wc;
+}
+
+static void xeno_console_send_xchar(struct tty_struct *tty, char ch)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&xeno_console_lock, flags);
+    x_char = ch;
+    __do_console_io();
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
+}
+
+static void xeno_console_throttle(struct tty_struct *tty)
+{
+    if ( I_IXOFF(tty) )
+        xeno_console_send_xchar(tty, STOP_CHAR(tty));
+}
+
+static void xeno_console_unthrottle(struct tty_struct *tty)
+{
+    if ( I_IXOFF(tty) )
+    {
+        if ( x_char != 0 )
+            x_char = 0;
+        else
+            xeno_console_send_xchar(tty, START_CHAR(tty));
+    }
+}
+
+static void xeno_console_flush_buffer(struct tty_struct *tty)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&xeno_console_lock, flags);
+    wc = wp = 0;
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
 }
 
-static inline int xeno_console_xmit(int ch)
+static inline int __xeno_console_put_char(int ch)
 {
-    char _ch = ch;
-    xen_console_write(NULL, &_ch, 1);
+    char _ch = (char)ch;
+
+    if ( start_info.flags & SIF_INITDOMAIN )
+    {
+        priv_conwrite(&_ch, 1);
+        return 1;
+    }
+
+    if ( (wp - wc) == WBUF_SIZE )
+        return 0;
+    wbuf[WBUF_MASK(wp++)] = _ch;
     return 1;
 }
 
@@ -127,31 +315,47 @@ static int xeno_console_write(struct tty_struct *tty, int from_user,
                        const u_char * buf, int count)
 {
     int i;
+    unsigned long flags;
 
     if ( from_user && verify_area(VERIFY_READ, buf, count) )
-    {
         return -EINVAL;
-    }
+
+    spin_lock_irqsave(&xeno_console_lock, flags);
 
     for ( i = 0; i < count; i++ )
     {
         char ch;
         if ( from_user )
-        {
             __get_user(ch, buf + i);
-        }
         else
-        {
             ch = buf[i];
-        }
-        xeno_console_xmit(ch);
+        if ( !__xeno_console_put_char(ch) )
+            break;
     }
+
+    if ( i != 0 )
+        __do_console_io();
+
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
+
     return i;
 }
 
 static void xeno_console_put_char(struct tty_struct *tty, u_char ch)
 {
-    xeno_console_xmit(ch);
+    unsigned long flags;
+    spin_lock_irqsave(&xeno_console_lock, flags);
+    (void)__xeno_console_put_char(ch);
+    spin_unlock_irqrestore(&xeno_console_lock, flags);
+}
+
+static void xeno_console_flush_chars(struct tty_struct *tty)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&xeno_console_lock, flags);
+
+    __do_console_io();
+    spin_unlock_irqrestore(&xeno_console_lock, flags);    
 }
 
 static int xeno_console_open(struct tty_struct *tty, struct file *filp)
@@ -167,12 +371,22 @@ static int xeno_console_open(struct tty_struct *tty, struct file *filp)
     }
 
     tty->driver_data = NULL;
+    if ( xeno_console_tty == NULL )
+    {
+        xeno_console_tty = tty;
+        wc = wp = 0;
+        __do_console_io();
+    }
+
+    xeno_console_use_count++;
 
     return 0;
 }
 
 static void xeno_console_close(struct tty_struct *tty, struct file *filp)
 {
+    if ( --xeno_console_use_count == 0 )
+        xeno_console_tty = NULL;
     MOD_DEC_USE_COUNT;
 }
 
@@ -180,36 +394,44 @@ int __init xeno_con_init(void)
 {
     memset(&xeno_console_driver, 0, sizeof(struct tty_driver));
     xeno_console_driver.magic           = TTY_DRIVER_MAGIC;
-    xeno_console_driver.driver_name     = "xeno_console";
-    xeno_console_driver.name            = "xencon";
+    xeno_console_driver.name            = "xencons";
     xeno_console_driver.major           = TTY_MAJOR;
     xeno_console_driver.minor_start     = XENO_TTY_MINOR;
     xeno_console_driver.num             = 1;
     xeno_console_driver.type            = TTY_DRIVER_TYPE_SERIAL;
     xeno_console_driver.subtype         = SERIAL_TYPE_NORMAL;
     xeno_console_driver.init_termios    = tty_std_termios;
-    xeno_console_driver.flags           = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+    xeno_console_driver.flags           = TTY_DRIVER_REAL_RAW;
     xeno_console_driver.refcount        = &xeno_console_refcount;
     xeno_console_driver.table           = xeno_console_table;
     xeno_console_driver.termios         = xeno_console_termios;
     xeno_console_driver.termios_locked  = xeno_console_termios_locked;
-    /* Functions */
+
     xeno_console_driver.open            = xeno_console_open;
     xeno_console_driver.close           = xeno_console_close;
     xeno_console_driver.write           = xeno_console_write;
     xeno_console_driver.write_room      = xeno_console_write_room;
     xeno_console_driver.put_char        = xeno_console_put_char;
+    xeno_console_driver.flush_chars     = xeno_console_flush_chars;
     xeno_console_driver.chars_in_buffer = xeno_console_chars_in_buffer;
+    xeno_console_driver.send_xchar      = xeno_console_send_xchar;
+    xeno_console_driver.flush_buffer    = xeno_console_flush_buffer;
+    xeno_console_driver.throttle        = xeno_console_throttle;
+    xeno_console_driver.unthrottle      = xeno_console_unthrottle;
 
     if ( tty_register_driver(&xeno_console_driver) )
+        panic("Couldn't register Xeno console driver\n");
+
+    if ( !(start_info.flags & SIF_INITDOMAIN) )
     {
-        printk(KERN_ERR "Couldn't register Xeno console driver\n");
-    }
-    else
-    {
-        printk("Xeno console successfully installed\n");
+        if ( evtchn_request_port(0, control_event) != 0 )
+            BUG();
+        /* Kickstart event delivery. */
+        control_event(0);
     }
 
+    printk("Xeno console successfully installed\n");
+    
     return 0;
 }
 
@@ -219,9 +441,10 @@ void __exit xeno_con_fini(void)
 
     ret = tty_unregister_driver(&xeno_console_driver);
     if ( ret != 0 )
-    {
         printk(KERN_ERR "Unable to unregister Xeno console driver: %d\n", ret);
-    }
+
+    if ( !(start_info.flags & SIF_INITDOMAIN) )
+        (void)evtchn_free_port(0);
 }
 
 module_init(xeno_con_init);
index cac02015582bffdb4c1fbab21b778e5dd9f60150..f060562529a98ac97d2bf27e093a7d36a88aa64b 100644 (file)
 #include <linux/devfs_fs_kernel.h>
 #include <linux/stat.h>
 #include <linux/poll.h>
-
-typedef void (*evtchn_receiver_t)(unsigned int);
-#define PORT_NORMAL     0x0000
-#define PORT_DISCONNECT 0x8000
-#define PORTIDX_MASK    0x7fff
-
-/* /dev/xen/evtchn resides at device number major=10, minor=200 */
-#define EVTCHN_MINOR 200
-
-/* /dev/xen/evtchn ioctls: */
-/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
-#define EVTCHN_RESET _IO('E', 1)
+#include <asm/evtchn.h>
 
 /* NB. This must be shared amongst drivers if more things go in /dev/xen */
 static devfs_handle_t xen_dev_dir;
@@ -110,18 +99,22 @@ int evtchn_free_port(unsigned int port)
 void evtchn_clear_port(unsigned int port)
 {
     unsigned int p = port & PORTIDX_MASK;
+    unsigned long flags;
+
+    spin_lock_irqsave(&lock, flags);
+
     if ( unlikely(port & PORT_DISCONNECT) )
     {
-        clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
-        wmb(); /* clear the source first, then our quenchmask */
         clear_bit(p, &disc_outstanding[0]);
+        clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
     }
     else
     {
-        clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
-        wmb(); /* clear the source first, then our quenchmask */
         clear_bit(p, &pend_outstanding[0]);
+        clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
     }
+
+    spin_unlock_irqrestore(&lock, flags);
 }
 
 static inline void process_bitmask(u32 *sel, 
@@ -168,7 +161,6 @@ static inline void process_bitmask(u32 *sel,
             }
         }
     }
-
 }
 
 static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -267,33 +259,37 @@ static ssize_t evtchn_read(struct file *file, char *buf,
         schedule();
     }
 
-    rc = -EFAULT;
-
-    /* Byte length of first chunk. May be truncated by ring wrap. */
+    /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
     if ( ((c ^ p) & RING_SIZE) != 0 )
+    {
         bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
+        bytes2 = RING_MASK(p) * sizeof(u16);
+    }
     else
+    {
         bytes1 = (p - c) * sizeof(u16);
+        bytes2 = 0;
+    }
 
-    /* Further truncate chunk length according to caller's maximum count. */
+    /* Truncate chunks according to caller's maximum byte count. */
     if ( bytes1 > count )
+    {
         bytes1 = count;
+        bytes2 = 0;
+    }
+    else if ( (bytes1 + bytes2) > count )
+    {
+        bytes2 = count - bytes1;
+    }
 
-    /* Copy the first chunk. */
-    if ( copy_to_user(buf, &ring[c], bytes1) != 0 )
-        goto out;
-
-    /* More bytes to copy? */
-    if ( count > bytes1 )
+    if ( copy_to_user(buf, &ring[RING_MASK(c)], bytes1) ||
+         ((bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2)) )
     {
-        bytes2 = RING_MASK(p) * sizeof(u16);
-        if ( bytes2 > count )
-            bytes2 = count;
-        if ( (bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2) )
-            goto out;
+        rc = -EFAULT;
+        goto out;
     }
 
-    ring_cons = (bytes1 + bytes2) / sizeof(u16);
+    ring_cons += (bytes1 + bytes2) / sizeof(u16);
 
     rc = bytes1 + bytes2;
 
@@ -465,6 +461,11 @@ static int __init init_module(void)
         return err;
     }
 
+    /* Kickstart servicing of notifications. */
+    evtchn_interrupt(0, NULL, NULL);
+
+    printk("Event-channel driver installed.\n");
+
     return 0;
 }
 
index cb64f1fdb410733f684508b7caf116ebec12a371..335756b050a616c8796cfd8be7529408f246580f 100644 (file)
@@ -531,6 +531,10 @@ int set_timeout_timer(void)
     if ( (timer = next_timer_event()) != NULL )
         alarm = __jiffies_to_st(timer->expires);
 
+    /* Tasks on the timer task queue expect to be executed on the next tick. */
+    if ( TQ_ACTIVE(tq_timer) )
+        alarm = __jiffies_to_st(jiffies + 1);
+
     /* Failure is pretty bad, but we'd best soldier on. */
     if ( HYPERVISOR_set_timer_op(alarm) != 0 )
         ret = -1;
diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h b/xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h
new file mode 100644 (file)
index 0000000..aa8375e
--- /dev/null
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * control_if.h
+ * 
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __CONTROL_IF_H__
+#define __CONTROL_IF_H__
+
+typedef struct {
+    u8 cmd_type;     /* echoed in response */
+    u8 cmd_subtype;  /* echoed in response */
+    u8 id;           /* echoed in response */
+    u8 length;       /* number of bytes in 'msg' */
+    unsigned char msg[60]; /* command-specific message data */
+} control_msg_t;
+
+#define CONTROL_RING_SIZE 8
+typedef unsigned int CONTROL_RING_IDX;
+#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
+
+typedef struct {
+    control_msg_t tx_ring[CONTROL_RING_SIZE]; /* guest-OS -> controller */
+    control_msg_t rx_ring[CONTROL_RING_SIZE]; /* controller -> guest-OS */
+    CONTROL_RING_IDX tx_req_prod, tx_resp_prod;
+    CONTROL_RING_IDX rx_req_prod, rx_resp_prod;
+} control_if_t;
+
+#define CMD_CONSOLE      0
+#define CMD_CONSOLE_DATA 0
+
+#endif /* __CONTROL_IF_H__ */
diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h b/xenolinux-2.4.25-sparse/include/asm-xeno/evtchn.h
new file mode 100644 (file)
index 0000000..88c278d
--- /dev/null
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * evtchn.h
+ * 
+ * Driver for receiving and demuxing event-channel signals.
+ * 
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __ASM_EVTCHN_H__
+#define __ASM_EVTCHN_H__
+
+typedef void (*evtchn_receiver_t)(unsigned int);
+#define PORT_NORMAL     0x0000
+#define PORT_DISCONNECT 0x8000
+#define PORTIDX_MASK    0x7fff
+
+/* /dev/xen/evtchn resides at device number major=10, minor=200 */
+#define EVTCHN_MINOR 200
+
+/* /dev/xen/evtchn ioctls: */
+/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
+#define EVTCHN_RESET _IO('E', 1)
+
+int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn);
+int evtchn_free_port(unsigned int port);
+void evtchn_clear_port(unsigned int port);
+
+
+#endif /* __ASM_EVTCHN_H__ */
index 075fdab17fee9298d116a272752c43e849b2bf85..bce5b9c24d7a7ac531f3090f2a80bef9427ca703 100644 (file)
@@ -432,6 +432,17 @@ static inline int HYPERVISOR_update_va_mapping(
     return ret;
 }
 
+static inline int HYPERVISOR_event_channel_op(void *op)
+{
+    int ret;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret) : "0" (__HYPERVISOR_event_channel_op),
+        "b" (op) : "memory" );
+
+    return ret;
+}
+
 static inline int HYPERVISOR_xen_version(int cmd)
 {
     int ret;